﻿
package projects.flashUpload {
	import flash.utils.getTimer;

	/**
	 * @author Marcelo Volmaro
	 */
	public final class Time {
		private var _startTime:uint;
		private var _length:uint;
		private var _now:uint;
		private var _graph:Array;
		private var _graphSize:uint;
		private var _rate:uint;
		private var _rateAvg:uint;
		private var _timeRemaining:Number;
		private var _diffTime:int;
		private var _elapsed:Number;

		public function Time(pGraphLength:uint = 10){
			_graphSize = pGraphLength;
			reset();
		}
		
		public function reset():void {
			_graph = [];
			_rate = _rateAvg = 0;
		}
		
		public function start(pLength:uint):void {
			_startTime = _diffTime = getTimer();
			_length = pLength;
		}
		
		public function update(pNow:uint):void {
			var now:uint = getTimer();
			var diff:uint = (pNow - _now) / (now  -_diffTime);
			var last:uint = _graph.unshift(Math.round(diff));
			
			_now = pNow;
			_rate = _rateAvg = 0;
			
			if (last > 1){
				if (last > _graphSize) last = _graphSize;
				
				var mean:Number = 0;
				var variance:Number = 0;
					
				for (var i:uint = 0; i < last; i++) {
					mean += _graph[i];
					variance += Math.pow(_graph[i] - mean, 2);
				}
				
				mean /= last;
				
				_rate = _rateAvg = Math.round(mean * 1000);
				
				if (last > 6) {
					var standard_dev:Number = Math.sqrt(variance / last);
					var deviation_range:Number = 2.0;
					
					var filtered_sum:Number = 0;
					var filtered_count:uint = 0;
					
					for (i = 0; i < last; i++) {
						var value:Number = (_graph[i] - mean) / standard_dev;
						
						if (value <= deviation_range && value >= -deviation_range) {
							filtered_sum += _graph[i];
							filtered_count++;
						}
					}
					
					_rateAvg = Math.round(filtered_sum / filtered_count * 1000);
					_timeRemaining = (_length - pNow) / _rateAvg;
				}
			}
			
			_elapsed = (now - _startTime) / 1000;
			_diffTime = now;
		}
		
		public function get elapsed():Number {
			return _elapsed;
		}
		
		public function get remaining():Number {
			return _timeRemaining;
		}
		
		public function get rate():uint {
			return _rate;
		}
		
		public function get averageRate():uint {
			return _rateAvg;
		}
	}
}
